# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: reporter\reports\scan_comparison.py
from reporter.reports.basic_template import NamedTempFileWithNormalizedWrite
from reporter.reports.basic_template import ReportTemplate
from io import StringIO
import jinja2


class ScanComparison(ReportTemplate):
    REPORT_NAME = "Scan Comparison"

    def parts(self):
        template_loader = jinja2.FileSystemLoader(searchpath="data/templates/reports/")
        template_env = jinja2.Environment(loader=template_loader)
        template_vars = {}
        template = template_env.get_template("scan_comparison_template.html")
        common_parts_template_vars = {}
        common_parts_template = template_env.get_template("common_parts_template.html")
        data = StringIO()
        data.write(common_parts_template.render({"template_part": "header"}))
        common_parts_template_vars["template_part"] = "body_start"
        common_parts_template_vars["report_name"] = self.REPORT_NAME
        common_parts_template_vars["date_generated"] = self.get_formatted_nowdate()
        data.write(common_parts_template.render(common_parts_template_vars))
        data.seek(0)
        yield data
        data = StringIO()
        if len(self.sources) < 2:
            template_vars["template_part"] = "warning"
            template_vars["message"] = "2 sources are needed for the comparison"
            data.write(template.render(template_vars))
            yield data
            data = StringIO()
        else:
            targets = []
            scan_session_id_list = []
            for source in self.sources:
                if source.source_type != "scan_result":
                    pass
                target_id = (
                    source.filter_target_id
                    if source.filter_target_id
                    else source.start_target_id
                )
                if target_id not in targets:
                    targets.append(target_id)
                if source.scan_session_id not in scan_session_id_list:
                    scan_session_id_list.append(source.scan_session_id)

            for target_id in targets:
                with NamedTempFileWithNormalizedWrite() as (file_undetected_alerts):
                    with NamedTempFileWithNormalizedWrite() as (file_new_alerts):
                        with NamedTempFileWithNormalizedWrite() as (
                            file_unchanged_alerts
                        ):
                            sources = [None, None]
                            for i in range(0, 2):
                                for source in self.sources:
                                    t = (
                                        source.filter_target_id
                                        if source.filter_target_id
                                        else source.start_target_id
                                    )
                                    if t == target_id:
                                        sources[i] = (
                                            source.scan_session_id
                                            == scan_session_id_list[i]
                                            and source
                                        )

                            if sources[0] is None or sources[1] is None:
                                continue
                            file_new_alerts.write(
                                template.render(
                                    {"template_part": "newly_discovered_issues_title"}
                                )
                            )
                            file_undetected_alerts.write(
                                template.render(
                                    {"template_part": "undetected_issues_title"}
                                )
                            )
                            file_unchanged_alerts.write(
                                template.render(
                                    {"template_part": "unchanged_issues_title"}
                                )
                            )
                            vulnerabilities_source2, alerts_count_source2 = self.get_vulnerabilities_and_alerts_count(
                                sources[1]
                            )
                            alerts_count_source1 = {3: 0, 2: 0, 1: 0, 0: 0}
                            for vulnerability_type, cnt in sources[
                                0
                            ].vulnerability_types():
                                alerts_count_source1[
                                    vulnerability_type["severity"]
                                ] += cnt
                                is_vuln_type_printed_in_unchanged = False
                                is_vuln_type_printed_in_undetected = False
                                for vulnerability, location, _ in sources[
                                    0
                                ].vulnerabilities(vtype=vulnerability_type):
                                    template_vars[
                                        "vulnerability_type"
                                    ] = vulnerability_type
                                    template_vars["vulnerability"] = vulnerability
                                    template_vars[
                                        "severity_string"
                                    ] = self.get_severity_string(
                                        vulnerability_type["severity"]
                                    )
                                    template_vars["vuln_source"] = (
                                        vulnerability.get("source") or ""
                                    )
                                    vulnerability["location"] = location
                                    template_vars["template_part"] = "affected_item"
                                    affected_item_string = template.render(
                                        template_vars
                                    )
                                    if (
                                        vulnerability["vuln_hash"]
                                        in vulnerabilities_source2
                                    ):
                                        if not is_vuln_type_printed_in_unchanged:
                                            template_vars["template_part"] = "alert"
                                            file_unchanged_alerts.write(
                                                template.render(template_vars)
                                            )
                                            is_vuln_type_printed_in_unchanged = True
                                        file_unchanged_alerts.write(
                                            affected_item_string
                                        )
                                        del vulnerabilities_source2[
                                            vulnerability["vuln_hash"]
                                        ]
                                    else:
                                        if not is_vuln_type_printed_in_undetected:
                                            template_vars["template_part"] = "alert"
                                            file_undetected_alerts.write(
                                                template.render(template_vars)
                                            )
                                            is_vuln_type_printed_in_undetected = True
                                        file_undetected_alerts.write(
                                            affected_item_string
                                        )

                                if is_vuln_type_printed_in_unchanged:
                                    file_unchanged_alerts.write(
                                        template.render(
                                            {"template_part": "alert_closing"}
                                        )
                                    )
                                if is_vuln_type_printed_in_undetected:
                                    file_undetected_alerts.write(
                                        template.render(
                                            {"template_part": "alert_closing"}
                                        )
                                    )

                            for vulnerability_type, cnt in sources[
                                1
                            ].vulnerability_types():
                                is_vuln_type_printed = False
                                for vulnerability, location, _ in sources[
                                    1
                                ].vulnerabilities(vtype=vulnerability_type):
                                    if (
                                        vulnerability["vuln_hash"]
                                        in vulnerabilities_source2
                                    ):
                                        if not is_vuln_type_printed:
                                            template_vars[
                                                "vulnerability_type"
                                            ] = vulnerability_type
                                            template_vars[
                                                "vulnerability"
                                            ] = vulnerability
                                            template_vars[
                                                "severity_string"
                                            ] = self.get_severity_string(
                                                vulnerability_type["severity"]
                                            )
                                            template_vars["vuln_source"] = (
                                                vulnerability.get("source") or ""
                                            )
                                            template_vars["template_part"] = "alert"
                                            file_new_alerts.write(
                                                template.render(template_vars)
                                            )
                                            is_vuln_type_printed = True
                                        vulnerability["location"] = location
                                        template_vars["vulnerability"] = vulnerability
                                        template_vars["template_part"] = "affected_item"
                                        affected_item_string = template.render(
                                            template_vars
                                        )
                                        file_new_alerts.write(affected_item_string)

                                if is_vuln_type_printed:
                                    file_new_alerts.write(
                                        template.render(
                                            {"template_part": "alert_closing"}
                                        )
                                    )

                            template_vars[
                                "scan_info1"
                            ] = self.get_well_formed_scan_info(sources[0])
                            if (
                                template_vars["scan_info1"]["host"]
                                not in template_vars["scan_info1"]["start_url"]
                            ):
                                template_vars["scan_info1"][
                                    "start_url_updated"
                                ] = template_vars["scan_info1"]["host"]
                            else:
                                template_vars["scan_info1"][
                                    "start_url_updated"
                                ] = template_vars["scan_info1"]["start_url"]
                            template_vars["scan_info1"][
                                "alerts_count"
                            ] = alerts_count_source1
                            template_vars["scan_info1"][
                                "threat_level"
                            ] = self.calculate_threat_level(alerts_count_source1)
                            template_vars[
                                "scan_info2"
                            ] = self.get_well_formed_scan_info(sources[1])
                            if (
                                template_vars["scan_info2"]["host"]
                                not in template_vars["scan_info2"]["start_url"]
                            ):
                                template_vars["scan_info2"][
                                    "start_url_updated"
                                ] = template_vars["scan_info2"]["host"]
                            else:
                                template_vars["scan_info2"][
                                    "start_url_updated"
                                ] = template_vars["scan_info2"]["start_url"]
                            template_vars["scan_info2"][
                                "alerts_count"
                            ] = alerts_count_source2
                            template_vars["scan_info2"][
                                "threat_level"
                            ] = self.calculate_threat_level(alerts_count_source2)
                            template_vars["template_part"] = "display_scan_info"
                            data.write(template.render(template_vars))
                            data.seek(0)
                            yield data
                            data = StringIO()
                            file_unchanged_alerts.seek(0)
                            yield file_unchanged_alerts
                            file_new_alerts.seek(0)
                            yield file_new_alerts
                            file_undetected_alerts.seek(0)
                            yield file_undetected_alerts

        data.write(common_parts_template.render({"template_part": "body_end"}))
        data.seek(0)
        yield data

    @staticmethod
    def get_vulnerabilities_and_alerts_count(source):
        alerts_count = {3: 0, 2: 0, 1: 0, 0: 0}
        vulnerabilities = {}
        if source is None:
            return (vulnerabilities, alerts_count)
        else:
            for vulnerability_type, cnt in source.vulnerability_types():
                alerts_count[vulnerability_type["severity"]] += cnt
                for vulnerability, location, _ in source.vulnerabilities(
                    vtype=vulnerability_type
                ):
                    vulnerability["location"] = location
                    vulnerabilities[vulnerability["vuln_hash"]] = vulnerability

            return (vulnerabilities, alerts_count)
